﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MoqContrib.AutoMock.CommonServiceLocator
{
	internal class ClassAnalyzer
	{
		public AutoMockHelper Helper { get; set; }

		internal T Construct<T>()
		{
			var ctors = typeof(T).GetConstructors()
				.OrderByDescending(x => x.GetParameters().Length);
			foreach (var ctor in ctors)
			{
				try
				{
					return (T)TryConstructor(ctor);
				}
				catch (UnmockableException) { }
				catch (TypeLoadException) { }
				catch (Exception e) {
					// The Castle.Core version that Moq currently uses has this exception marked
					// as internal. I know that now (5/2011) the master branch of Castle.Core has
					// this issue fixed. But we're totally relient on when Moq upgrades...
					if (e.GetType().FullName == "Castle.DynamicProxy.Generators.GeneratorException")
					{
						// swallow exception
					}
					else throw new ApplicationException(@"Exception thrown in a constructor.
See inner exception for details", e);
				}
			}
			throw new ArgumentException(string.Format(
				@"Could not find a public constructor for {0} that I know how to resolve",
				typeof(T).Name));
		}

		private object TryConstructor(System.Reflection.ConstructorInfo ctor)
		{
			var @params = ctor.GetParameters();
			var args = new object[@params.Length];
			for (int i = 0; i < @params.Length; i++)
			{
				args[i] = Helper.Of(@params[i].ParameterType);
			}
			return ctor.Invoke(args);
		}
	}
}
